﻿// WindowsProject1.cpp : 定义应用程序的入口点。
//

#include "framework.h"
#include "WindowsProject1.h"
#include "math.h" 
#include "Mmsystem.h" 
#include "Windowsx.h"
#include "stdio.h"
#include "commctrl.h"
#include "gl\glew.h"
#include "gl\GLAux.h"
#include "gl\glut.h"
#include "whyOpenGLDLL.h" 
const float PI = 3.14159265357f;
  
BOOL           bRBUTTONDOWN;//鼠标右键是否按下
 
GLfloat     ztrans = -1.0f;
GLfloat     xtrans = 0.0f;
  
GLuint        uBMModCallList[1000];//白模模型显示列表 
DWORD       dwModN;
 
HDC			hDC = NULL;								 
HGLRC		hRC = NULL;								 
HWND		hWnd = NULL;								 
HINSTANCE	hInstance = NULL;							 

bool keys[256], keypressed[256];					
bool bdraw=0;
bool active = TRUE;										 
bool fullscreen = TRUE;								 

glObject	obj[500];								 
 
DWORD       dwMainWinWidth, dwMainWinHeight;

float xxrot, yyrot = 0.0f;
float zzrot = 0.0f;
int oldx, oldy;

float LightPos[] = { 0,  100, 100, 1.0f };			//光照位置
 
LRESULT	CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM);	
 
//设置材质
void _SetMaterial()
{
	float MatAmb[] = { 0.5, 0.5, 0.5, 0.5 };
	float MatDif[] = { 0.5, 0.5, 0.5, 0.5 };
	float MatSpc[] = { 10.0f, 10.0f, 10.0f };			 
	float MatShn[] = { 100.0f };							 

	glMaterialfv(GL_FRONT, GL_AMBIENT, MatAmb);		//设置全局材质
	glMaterialfv(GL_FRONT, GL_DIFFUSE, MatDif);		//设置漫反射材质
	glMaterialfv(GL_FRONT, GL_SPECULAR, MatSpc);	//设置镜面材质
	glMaterialfv(GL_FRONT, GL_SHININESS, MatShn);	//设置亮度
}

//点光(泛光)
void _SetEnvLight()
{
	float LightAmb[] = { 1, 1, 1, 1.0f };
	float LightDif[] = { 1, 1, 1, 1.0f };
	float LightSpc[] = { 1, 1, 1.0f, 1.0f };
	glLightfv(GL_LIGHT1, GL_POSITION, LightPos);	//设置光源位置
	glLightfv(GL_LIGHT1, GL_AMBIENT, LightAmb);			//设置全局光
	glLightfv(GL_LIGHT1, GL_DIFFUSE, LightDif);			//设置漫反射光
	glLightfv(GL_LIGHT1, GL_SPECULAR, LightSpc);		//设置镜面光
	glEnable(GL_LIGHT1);						//启用光源1
	glEnable(GL_LIGHTING);						//启用光源
}
 
//设置OpenGL窗口的视景体（非OpenGL功能）
GLvoid ReSizeGLScene(GLsizei width, GLsizei height)		 
{
	if (height == 0)								 
	{
		height = 1;									 
	}

	glViewport(0, 0, width, height);					 

	glMatrixMode(GL_PROJECTION);					 
	glLoadIdentity();							 

 
	gluPerspective(45.0f, (GLfloat)width / (GLfloat)height, 0.1f, 5000.0f);

	dwMainWinWidth = width;
	dwMainWinHeight = height;

	glMatrixMode(GL_MODELVIEW);					 
	glLoadIdentity();								 
}
 
//画白模场景
BOOL _DrawBMRoad()
{ 
	//场景平移微调
	glTranslatef(0.0, -40.0, -140.0f);
	//场景旋转
	glRotatef(xxrot, 0.0f, 1.0f, 0.0f);//自由旋转角度
	/////////////////////画整个场景//////////////
	for (int i = 1; i <= dwModN; i++)
	{
		glCallList(uBMModCallList[i]);
	}
	/////////////////////画整个场景//////////////
	return 0;
}

int DrawGLScene(DWORD _dwRenderMode)						 
{
	static int i = 0;
	//设置背景颜色
	glClearColor(0.0, 0.0, 0.0, 0.0f);
	glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);
	glMatrixMode(GL_MODELVIEW);
	glLoadIdentity();
	//平移场景
	glTranslatef(xtrans, -0.5f, ztrans);
	//画模型函数
	_DrawBMRoad(); 
	return TRUE;						 
}

//读取模型
BOOL _LoadModel()
{

	//模型计数清零
	DWORD     _dwModIndex;
	_dwModIndex = 0;
	// 
	char _szTemp[50], _szTemp1[50];
	//获得模型数量
	dwModN = GetPrivateProfileInt(TEXT("mx"),
		TEXT("num"),
		0,
		TEXT(".\\modindex.ini"));
	for (int i = 1; i <= dwModN; i++)
	{ 
		//获得模型白模材质路径
		sprintf_s(_szTemp,50, "%dtexbm", i);
		GetPrivateProfileStringA("mx",
			_szTemp,
			"(NULL)",
			_szTemp1,
			50,
			".\\modindex.ini");
		DWORD _dwTex1;
		if (!why3DLoadTextures(_szTemp1, &_dwTex1))//读取图片材质
		{
			MessageBoxA(0, "材质图片不存在或格式错误", 0, 0);
			SetLastError(0x00000005);
			return FALSE;
		}
		//获得模型路径
		sprintf_s(_szTemp,50, "%dmod3p", i);
		GetPrivateProfileStringA("mx",
			_szTemp,
			"(NULL)",
			_szTemp1,
			50,
			".\\modindex.ini");
		ObjectInfo  _stModTemp;
		//载入图片的OBJ模型
		if (!why3DLoad3POBJFile(_szTemp1, &_stModTemp,0, 0))
		{
			SetLastError(0x00000001);
			return FALSE;
		} 
		//模型计数自增
		_dwModIndex++;
		//为每一个模型建立一个正常显示列表
		uBMModCallList[_dwModIndex] = glGenLists(1);
		//产生新显示列表
		glNewList(uBMModCallList[_dwModIndex], GL_COMPILE);
		//绑定纹理
		glBindTexture(GL_TEXTURE_2D, _dwTex1);
		//绘制模型的所有三角形
		why3DDrawOBJObject3P(&_stModTemp, 0,
			2.0f, 1.0f, 1.0f,
			-1.0f, 0.0f, 2.0f,
			90.0f, 1.0f, 0.0f, 0.0f, 0, 0, 0, 0);
		//完成显示列表
		glEndList();
	}
	return TRUE;
} 

//初始化
int InitGL(GLvoid)									 
{
	glewInit();
	static BOOL _bLoadTreeModel = FALSE;
	if (_bLoadTreeModel == FALSE)
	{
		if (!_LoadModel())
		{ 
			return TRUE;
		}
		_bLoadTreeModel = TRUE;
	}
	//平滑模式
	glShadeModel(GL_SMOOTH);
	//黑色背景
	glClearColor(0.0f, 0.0f, 0.0f, 0.5f);
	//清理深度缓冲区
	glClearDepth(1.0f);
	//清理模板
	glClearStencil(0);
	//启动深度测试
	glEnable(GL_DEPTH_TEST);
	glDepthFunc(GL_LEQUAL);
	glHint(GL_PERSPECTIVE_CORRECTION_HINT, GL_NICEST);
	//点大小
	glEnable(GL_POINT_SMOOTH);
	glPointSize(10.0f);
	//泛光源
	_SetEnvLight();
	//设置材质
	_SetMaterial();
	//启动纹理
	glEnable(GL_TEXTURE_2D);
	return TRUE;										// Initialization Went OK
}

void ProcessKeyboard()									// Process Key Presses
{
	 //场景前移
	if (keys[VK_UP])
	{
		ztrans += 1.0f;

	} 
	//场景后移
	if (keys[VK_DOWN])
	{
		ztrans -= 1.0f;

	}
	//场景zuo移
	if (keys[VK_LEFT])
	{
		xtrans += 0.5f;

	}
	//场景you移
	if (keys[VK_RIGHT])
	{
		xtrans -= 0.5f;

	}
}


//关闭OpenGL环境（非OpenGL功能 不用看）
GLvoid KillGLWindow(GLvoid)
{
	if (hRC)
	{
		if (!wglMakeCurrent(NULL, NULL))
		{
			MessageBoxA(NULL, "Release Of DC And RC Failed.", "SHUTDOWN ERROR", MB_OK | MB_ICONINFORMATION);
		}

		if (!wglDeleteContext(hRC))
		{
			MessageBoxA(NULL, "Release Rendering Context Failed.", "SHUTDOWN ERROR", MB_OK | MB_ICONINFORMATION);
		}
		hRC = NULL;
	}

	if (hDC && !ReleaseDC(hWnd, hDC))
	{
		MessageBoxA(NULL, "Release Device Context Failed.", "SHUTDOWN ERROR", MB_OK | MB_ICONINFORMATION);
		hDC = NULL;
	}

	if (hWnd && !DestroyWindow(hWnd))
	{
		MessageBoxA(NULL, "Could Not Release hWnd.", "SHUTDOWN ERROR", MB_OK | MB_ICONINFORMATION);
		hWnd = NULL;
	}

	if (fullscreen)
	{
		ChangeDisplaySettings(NULL, 0);
		ShowCursor(TRUE);
	}

	if (!UnregisterClass(TEXT("why-OpenGL"), hInstance))
	{
		MessageBox(0,
			TEXT("Could Not Unregister Class."),
			TEXT("SHUTDOWN ERROR"),
			MB_OK | MB_ICONINFORMATION);
		hInstance = NULL;
	}
}

//创建OpenGL环境（非OpenGL功能 不用看）
BOOL CreateGLWindow(WCHAR* title, int width, int height, int bits, bool fullscreenflag)
{
	GLuint		PixelFormat;							// Holds The Results After Searching For A Match
	WNDCLASS	wc;										// Windows Class Structure
	DWORD		dwExStyle;								// Window Extended Style
	DWORD		dwStyle;								// Window Style

	fullscreen = fullscreenflag;							// Set The Global Fullscreen Flag

	hInstance = GetModuleHandle(NULL);		// Grab An Instance For Our Window
	wc.style = CS_HREDRAW | CS_VREDRAW | CS_OWNDC;	// Redraw On Size, And Own DC For Window.
	wc.lpfnWndProc = (WNDPROC)WndProc;			// WndProc Handles Messages
	wc.cbClsExtra = 0;							// No Extra Window Data
	wc.cbWndExtra = 0;							// No Extra Window Data
	bdraw = 0;
	wc.hInstance = hInstance;					// Set The Instance
	wc.hIcon = LoadIcon(NULL, IDI_WINLOGO);	// Load The Default Icon
	wc.hCursor = LoadCursor(NULL, IDC_ARROW);	// Load The Arrow Pointer
	wc.hbrBackground = NULL;							// No Background Required For GL
	wc.lpszMenuName = NULL;							// We Don't Want A Menu
	wc.lpszClassName = TEXT("why-OpenGL");						// Set The Class Name

	if (!RegisterClass(&wc))							// Attempt To Register The Window Class
	{
		MessageBoxA(NULL, "Failed To Register The Window Class.", "ERROR", MB_OK | MB_ICONEXCLAMATION);
		return FALSE;									// Return FALSE
	}

	if (fullscreen)										// Attempt Fullscreen Mode?
	{
		DEVMODE dmScreenSettings;						// Device Mode
		memset(&dmScreenSettings, 0, sizeof(dmScreenSettings));	// Makes Sure Memory's Cleared
		dmScreenSettings.dmSize = sizeof(dmScreenSettings);	// Size Of The Devmode Structure
		dmScreenSettings.dmPelsWidth = width;		// Selected Screen Width
		dmScreenSettings.dmPelsHeight = height;		// Selected Screen Height
		dmScreenSettings.dmBitsPerPel = bits;			// Selected Bits Per Pixel
		dmScreenSettings.dmFields = DM_BITSPERPEL | DM_PELSWIDTH | DM_PELSHEIGHT;

		// Try To Set Selected Mode And Get Results.  NOTE: CDS_FULLSCREEN Gets Rid Of Start Bar.
		if (ChangeDisplaySettings(&dmScreenSettings, CDS_FULLSCREEN) != DISP_CHANGE_SUCCESSFUL)
		{
			// If The Mode Fails, Offer Two Options.  Quit Or Use Windowed Mode.
			if (MessageBoxA(NULL, "The Requested Fullscreen Mode Is Not Supported By\nYour Video Card. Use Windowed Mode Instead?", "  GL", MB_YESNO | MB_ICONEXCLAMATION) == IDYES)
			{
				fullscreen = FALSE;						// Windowed Mode Selected.  Fullscreen = FALSE
			}
			else										// Otherwise
			{
				// Pop Up A Message Box Letting User Know The Program Is Closing.
				MessageBoxA(NULL, "Program Will Now Close.", "ERROR", MB_OK | MB_ICONSTOP);
				return FALSE;							// Return FALSE
			}
		}
	}

	if (fullscreen)										// Are We Still In Fullscreen Mode?
	{
		dwExStyle = WS_EX_APPWINDOW;						// Window Extended Style
		dwStyle = WS_POPUP | WS_CLIPSIBLINGS | WS_CLIPCHILDREN;	// Windows Style
		ShowCursor(FALSE);								// Hide Mouse Pointer
	}
	else
	{
		dwExStyle = WS_EX_APPWINDOW | WS_EX_WINDOWEDGE;	// Window Extended Style
		dwStyle = WS_OVERLAPPEDWINDOW | WS_CLIPSIBLINGS | WS_CLIPCHILDREN;	// Windows Style
	}

	// Create The Window
	if (!(hWnd = CreateWindowEx(dwExStyle,				// Extended Style For The Window
		TEXT("why-OpenGL"),				// Class Name
		title,					// Window Title
		dwStyle,				// Window Style
		0, 0,					// Window Position
		width, height,			// Selected Width And Height
		NULL,					// No Parent Window
		NULL,					// No Menu
		hInstance,				// Instance
		NULL)))					// Dont Pass Anything To WM_CREATE
	{
		KillGLWindow();									// Reset The Display
		MessageBoxA(NULL, "Window Creation Error.", "ERROR", MB_OK | MB_ICONEXCLAMATION);
		return FALSE;									// Return FALSE
	}

	static	PIXELFORMATDESCRIPTOR pfd =					// pfd Tells Windows How We Want Things To Be
	{
		sizeof(PIXELFORMATDESCRIPTOR),					// Size Of This Pixel Format Descriptor
		1,												// Version Number
		PFD_DRAW_TO_WINDOW |							// Format Must Support Window
		PFD_SUPPORT_OPENGL |							// Format Must Support OpenGL
		PFD_DOUBLEBUFFER,								// Must Support Double Buffering
		PFD_TYPE_RGBA,									// Request An RGBA Format
		bits,											// Select Our Color Depth
		0, 0, 0, 0, 0, 0,								// Color Bits Ignored
		0,												// No Alpha Buffer
		0,												// Shift Bit Ignored
		0,												// No Accumulation Buffer
		0, 0, 0, 0,										// Accumulation Bits Ignored
		16,												// 16Bit Z-Buffer (Depth Buffer)  
		1,												// Use Stencil Buffer ( * Important * )
		0,												// No Auxiliary Buffer
		PFD_MAIN_PLANE,									// Main Drawing Layer
		0,												// Reserved
		0, 0, 0											// Layer Masks Ignored
	};

	if (!(hDC = GetDC(hWnd)))								// Did We Get A Device Context?
	{
		KillGLWindow();									// Reset The Display
		MessageBoxA(NULL, "Can't Create A GL Device Context.", "ERROR", MB_OK | MB_ICONEXCLAMATION);
		return FALSE;									// Return FALSE
	}

	if (!(PixelFormat = ChoosePixelFormat(hDC, &pfd)))		// Did Windows Find A Matching Pixel Format?
	{
		KillGLWindow();									// Reset The Display
		MessageBoxA(NULL, "Can't Find A Suitable PixelFormat.", "ERROR", MB_OK | MB_ICONEXCLAMATION);
		return FALSE;									// Return FALSE
	}

	if (!SetPixelFormat(hDC, PixelFormat, &pfd))			// Are We Able To Set The Pixel Format? 
	{
		KillGLWindow();									// Reset The Display
		MessageBoxA(NULL, "Can't Set The PixelFormat.", "ERROR", MB_OK | MB_ICONEXCLAMATION);
		return FALSE;									// Return FALSE
	}

	if (!(hRC = wglCreateContext(hDC)))					// Are We Able To Get A Rendering Context?
	{
		KillGLWindow();									// Reset The Display
		MessageBoxA(NULL, "Can't Create A GL Rendering Context.", "ERROR", MB_OK | MB_ICONEXCLAMATION);
		return FALSE;									// Return FALSE
	}

	if (!wglMakeCurrent(hDC, hRC))						// Try To Activate The Rendering Context
	{
		KillGLWindow();									// Reset The Display
		MessageBoxA(NULL, "Can't Activate The GL Rendering Context.", "ERROR", MB_OK | MB_ICONEXCLAMATION);
		return FALSE;									// Return FALSE
	}

	ShowWindow(hWnd, SW_SHOW);							// Show The Window
	SetForegroundWindow(hWnd);							// Slightly Higher Priority
	SetFocus(hWnd);										// Sets Keyboard Focus To The Window
	ReSizeGLScene(width, height);						// Set Up Our Perspective GL Screen

	if (!InitGL())										// Initialize Our Newly Created GL Window
	{
		KillGLWindow();									// Reset The Display
		MessageBoxA(NULL, "Initialization Failed.", "ERROR", MB_OK | MB_ICONEXCLAMATION);
		return FALSE;									// Return FALSE
	}

	return TRUE;										// Success
}

//入口函数（非OpenGL功能 不用看）
LRESULT CALLBACK WndProc(HWND	hWnd,				// Handle For This Window
	UINT	uMsg,				// Message For This Window
	WPARAM	wParam,				// Additional Message Information
	LPARAM	lParam)				// Additional Message Information
{
	switch (uMsg)										// Check For Windows Messages
	{
	case WM_ACTIVATE:								// Watch For Window Activate Message
	{
		if (!HIWORD(wParam))						// Check Minimization State
		{
			active = TRUE;							// Program Is Active
		}
		else										// Otherwise
		{
			active = FALSE;							// Program Is No Longer Active
		}

		return 0;									// Return To The Message Loop
	}

	case WM_SYSCOMMAND:								// Intercept System Commands
	{
		switch (wParam)								// Check System Calls
		{
		case SC_SCREENSAVE:						// Screensaver Trying To Start?
		case SC_MONITORPOWER:					// Monitor Trying To Enter Powersave?
			return 0;								// Prevent From Happening
		}
		break;										// Exit
	}

	case WM_CLOSE:									// Did We Receive A Close Message?
	{ 
		PostQuitMessage(0);							// Send A Quit Message
		return 0;									// Jump Back
	}

	case WM_KEYDOWN:								// Is A Key Being Held Down?
	{
		keys[wParam] = TRUE;						// If So, Mark It As TRUE
		return 0;									// Jump Back
	}



	case WM_RBUTTONDOWN:
		POINT _stPOINT;
		GetCursorPos(&_stPOINT);

		oldx = _stPOINT.x;
		oldy = _stPOINT.y;

		bRBUTTONDOWN = TRUE;
		return TRUE;


	case WM_RBUTTONUP:
		bRBUTTONDOWN = FALSE;
		return TRUE;


	case WM_KEYUP:									// Has A Key Been Released?
	{
		keys[wParam] = FALSE;						// If So, Mark It As FALSE
		return 0;									// Jump Back
	}

	case WM_SIZE:									// Resize The OpenGL Window
	{
		ReSizeGLScene(LOWORD(lParam), HIWORD(lParam));  // LoWord=Width, HiWord=Height
		return 0;									// Jump Back
	}
	}

	// Pass All Unhandled Messages To DefWindowProc
	return DefWindowProc(hWnd, uMsg, wParam, lParam);
}

//入口函数（非OpenGL功能）
int WINAPI WinMain(HINSTANCE	hInstance,				// Instance
	HINSTANCE	hPrevInstance,			// Previous Instance
	LPSTR		lpCmdLine,				// Command Line Parameters
	int			nCmdShow)				// Window Show State
{
	MSG		msg;										// Windows Message Structure
	BOOL	done = FALSE;									// Bool Variable To Exit Loop


	fullscreen = FALSE;
	WCHAR t[50];
	if (!CreateGLWindow(t, 800, 600, 32, fullscreen))
	{
		return 0;										// Quit If Window Was Not Created
	}
	//处理窗口消息循环
	while (!done)										// Loop That Runs While done=FALSE
	{
		if (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE))		// Is There A Message Waiting?
		{
			if (msg.message == WM_QUIT)					// Have We Received A Quit Message?
			{
				done = TRUE;								// If So done=TRUE
			}
			else										// If Not, Deal With Window Messages
			{
				TranslateMessage(&msg);					// Translate The Message
				DispatchMessage(&msg);					// Dispatch The Message
			}
		}
		else											// If There Are No Messages
		{
			// Draw The Scene.  Watch For ESC Key And Quit Messages From DrawGLScene()
			if (active && keys[VK_ESCAPE])				// Active?  Was There A Quit Received?
			{
				done = TRUE;								// ESC or DrawGLScene Signalled A Quit
			}
			else										// Not Time To Quit, Update Screen
			{
				LONG _sw, _sh;
				_sw = GetSystemMetrics(SM_CXSCREEN);//获得屏幕宽
				_sh = GetSystemMetrics(SM_CYSCREEN);//获得屏幕高
				if (bRBUTTONDOWN)//如果右键按下
				{
					//得到当前光标位置
					POINT _stPOINT;
					GetCursorPos(&_stPOINT);
					//计算光标的移动距离
					int _x, _y;
					_x = -(oldx - _stPOINT.x);
					_y = -(oldy - _stPOINT.y);

					//传递距离给旋转变量
					xxrot += _x;
					yyrot += _y;

					//得到新的光标位置
					oldx = _stPOINT.x;
					oldy = _stPOINT.y;

				}
				DrawGLScene(GL_RENDER);							// Draw GL Scene
				SwapBuffers(hDC);						// Swap Buffers (Double Buffering)
				ProcessKeyboard();						// Process Key Presses
			}
		}
	}

	// Shutdown
	KillGLWindow();										// Kill The Window
	return (msg.wParam);								// Exit The Program
}
